package com.sky.utils;

import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.SecretKeySpec;
import java.security.SecureRandom;
import java.security.spec.KeySpec;
import java.util.Base64;

public class EncryptDecryptUtil {

    private static final int AES_KEY_SIZE = 256;
    private static final int SALT_BYTES = 64;
    private static final int PBKDF2_ITERATIONS = 10000;
    private static final String CIPHER_TRANSFORMATION_CBC = "AES/CBC/PKCS5Padding";

    // 生成随机盐
    private static byte[] generateSalt() {
        SecureRandom random = new SecureRandom();
        byte[] salt = new byte[SALT_BYTES];
        random.nextBytes(salt);
        return salt;
    }

    // 使用加盐哈希和PBKDF2密钥拉伸技术生成AES密钥
    private static SecretKey generateAESKey(String password, byte[] salt) throws Exception {
        KeySpec spec = new PBEKeySpec(password.toCharArray(), salt, PBKDF2_ITERATIONS, AES_KEY_SIZE);
        SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256");
        byte[] hash = factory.generateSecret(spec).getEncoded();
        return new SecretKeySpec(hash, "AES");
    }

    // 生成随机IV
    private static IvParameterSpec generateIv(int size) {
        SecureRandom random = new SecureRandom();
        byte[] iv = new byte[size];
        random.nextBytes(iv);
        return new IvParameterSpec(iv);
    }

    // AES CBC模式加密
    public String encryptDataCBC(String data, String password) throws Exception {
        byte[] salt = generateSalt();
        SecretKey secretKey = generateAESKey(password, salt);
        IvParameterSpec ivSpec = generateIv(16); // AES块大小为16字节
        Cipher cipher = Cipher.getInstance(CIPHER_TRANSFORMATION_CBC);
        cipher.init(Cipher.ENCRYPT_MODE, secretKey, ivSpec);
        byte[] encryptedBytes = cipher.doFinal(data.getBytes());

        // 将盐、IV和加密数据编码为Base64字符串
        String saltBase64 = Base64.getEncoder().encodeToString(salt);
        String ivBase64 = Base64.getEncoder().encodeToString(ivSpec.getIV());
        String encryptedDataBase64 = Base64.getEncoder().encodeToString(encryptedBytes);

        return saltBase64 + ":" + ivBase64 + ":" + encryptedDataBase64;
    }

    // AES CBC模式解密
    public String decryptDataCBC(String encryptedData, String password) throws Exception {
        String[] parts = encryptedData.split(":");
        if (parts.length != 3) {
            throw new IllegalArgumentException("Invalid encrypted data format.");
        }
        byte[] salt = Base64.getDecoder().decode(parts[0]);
        byte[] iv = Base64.getDecoder().decode(parts[1]);
        byte[] encryptedBytes = Base64.getDecoder().decode(parts[2]);

        SecretKey secretKey = generateAESKey(password, salt);
        IvParameterSpec ivSpec = new IvParameterSpec(iv);
        Cipher cipher = Cipher.getInstance(CIPHER_TRANSFORMATION_CBC);
        cipher.init(Cipher.DECRYPT_MODE, secretKey, ivSpec);
        byte[] decryptedBytes = cipher.doFinal(encryptedBytes);

        return new String(decryptedBytes);
    }

}